package com.byron.media.server.handlers;

import com.byron.media.server.MediaServer;
import com.byron.media.server.enums.Args;
import com.byron.media.server.logic.HandlerContainer;
import com.byron.media.server.model.MediaData;
import com.byron.media.server.model.MediaHeaderObj;
import com.byron.media.server.utils.JsonUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
//@ChannelHandler.Sharable
public class MediaSession extends ChannelInboundHandlerAdapter implements ISession{

    private String groupName;   // 该连接所在的组（非代理服务器有效）

    private boolean sender;     // 是否是发送端

    private boolean active;     // 是否注册

    private String device;      // 设备号

    private boolean proxy;      // TODO 是否为代理服务器

    private Queue<Long> history; // 历史发送的包名

    private ChannelHandlerContext context;

    private SessionContainer sessionContainer;

    private MediaServer mediaServer;

    public MediaSession(MediaServer mediaServer, SessionContainer sessionContainer){
        this.sessionContainer = sessionContainer;
        this.mediaServer = mediaServer;
        this.history = new ConcurrentLinkedQueue<>();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        if(context == null){
            context = ctx;
        }

        if(msg instanceof String){
            String json = (String) msg;
            MediaHeaderObj header = JsonUtils.fromJson(json, MediaHeaderObj.class);

            if(header.getCmd() == null){
                return;
            }

            String cmd = (String) header.getCmd().get("cmd");
            if(cmd == null){
                return;
            }
            HandlerContainer.getInstance().handle(cmd, this, ctx, header);

        } else if(active){
            ctx.fireChannelRead(msg);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
//        ctx.fireChannelActive();
        ctx.fireChannelReadComplete();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        if(!isActive()){
            return;
        }

        if(!isProxy()){
            inactive(device, groupName, sender);
            return;
        }

        // 如果是代理服务器离线，则从sessionController中移除
        sessionContainer.removeFromProxyClient(this);

    }

    public String getGroupName() {
        return groupName;
    }

    /**
     * 输出数据
     */
    @Override
    public void write(Object data) {
        if(context == null){
            return;
        }
        if(data.getClass() == MediaData.class){
            MediaData mediaData = (MediaData) data;
            if(history.contains(mediaData.getSeq())){
                return;
            }
            history.offer(mediaData.getSeq());
            if(history.size() > 5){
                history.poll();
            }
        }
        context.writeAndFlush(data);
    }

    /**
     * 取消激活，断线时需要操作
     */
    public void inactive(String device, String groupName, boolean sender){

        if(isProxy()){
            log.info("代理客户端 " + device + " 断开连接");
            if(sender){
                sessionContainer.cleanIframe(groupName);
                return;
            }
            sessionContainer.removeFromGroup(device, groupName);
            return;
        }

        device = this.device;
        groupName = this.groupName;
        sender = this.sender;

        log.info("流媒体客户端 " + device + " 断开连接");
        if(isSender()){
            sessionContainer.cleanIframe(this.groupName);
        } else {
            sessionContainer.removeFromGroup(this.device, this.groupName);
        }

        MediaHeaderObj unregObj = null;
        if(mediaServer.isProxyServer()){

            unregObj = new MediaHeaderObj();
            unregObj.getCmd().put("cmd", "unreg");
            unregObj.getCmd().put("respone", 0);
            unregObj.getArgs().put(Args.GROUP_NAME, groupName);
            unregObj.getArgs().put(Args.PROXY, true);
            unregObj.getArgs().put(Args.SENDER, sender);
            unregObj.getDevice().put("id", device);

            sessionContainer.sendToMainServer(unregObj);
        }

        if(unregObj == null){
            unregObj = new MediaHeaderObj();
            unregObj.getCmd().put("cmd", "unreg");
            unregObj.getCmd().put("respone", 0);
            unregObj.getArgs().put(Args.GROUP_NAME, groupName);
            unregObj.getArgs().put(Args.PROXY, true);
            unregObj.getArgs().put(Args.SENDER, sender);
            unregObj.getDevice().put("id", device);
        }
        sessionContainer.sendToAllProxyClient(unregObj);
    }

    /**
     * 激活线路
     */
    public void active(String device, String groupName, boolean sender, boolean proxy) {

        if(proxy){
            this.proxy = true;
            this.active = true;
            if(device != null && groupName != null){
                ProxyMediaSession proxySession = new ProxyMediaSession(sessionContainer, groupName, this);
                proxySession.beActive(device, groupName, sender);
                log.info("代理客户端 " + device + " 连接成功");
            } else {
                log.info("代理服务器 连接成功");

                // 添加到sessionContainer管理
                sessionContainer.addToProxyClient(this);
            }

            return;
        }


        this.groupName = groupName;
        this.sender = sender;
        this.device = device;
        if(!sender){
            // TODO 向接受者发送前一张I帧
            sessionContainer.sendLastIframe(groupName, this);
            sessionContainer.addToGroup(device, groupName, this);
        }
        this.active = true;
        log.info("流媒体客户端 " + device + " 连接成功");

        // 如果本机是代理服务器，还需要向上层服务器发送注册
        if(mediaServer.isProxyServer()){
            MediaHeaderObj header = new MediaHeaderObj();
            header.getCmd().put("cmd", "reg");
            header.getCmd().put("respone", 0);
            header.getArgs().put(Args.GROUP_NAME, groupName);
            header.getArgs().put(Args.PROXY, true);
            header.getArgs().put(Args.SENDER, sender);
            header.getDevice().put("id", device);

//                String json = JsonUtils.toJson(header);
            sessionContainer.sendToMainServer(header);
        }
    }

    public boolean isSender() {
        return sender;
    }

    public boolean isActive(){
        return active;
    }

    public String getDevice() {
        return device;
    }

    public boolean isProxy() {
        return proxy;
    }

}
